#include "qipmsg.h"
#include "ui_qipmsg.h"
#include <unistd.h>

#include "filetransworker.h"

extern quint32 g_pkg_seq;

/**
 * @brief QIPMSG::QIPMSG  构造函数
 * @param parent
 */
QIPMSG::QIPMSG(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::QIPMSG)
{
    // 使用翻译器
    qIpMsgLang = new QTranslator();
    qIpMsgLang-> load(":/translations/translations_zh.qm");
    QApplication::instance()->installTranslator(qIpMsgLang);

    // 自身用户信息类
    mSelf.userId  = fromUnicode(QString(QHostInfo::localHostName()));
    mSelf.userVer = fromUnicode(QString(IPMSG_VERSION));

    mSelf.userPktSeq    = 0;
    mSelf.userHostName  = fromUnicode(QString(QHostInfo::localHostName()));
    mSelf.userNickName  = fromUnicode(QString(QHostInfo::localHostName()));
    mSelf.userGroupName = fromUnicode(QString(tr(IPMSG_DEFAULT_GROUPNAME)));

    mStartIp = QHostAddress("192.168.101.1"  ).toIPv4Address();
    mEndIp   = QHostAddress("192.168.101.254").toIPv4Address();

    ui->setupUi(this);

    // 文件服务器
    fileServer = new IpMsgFileServer();

    qIpMsgStatus("");

    ui->menuUser->setTitle(tr("User"));
    ui->actionRefresh->setText(tr("Refresh"));
    ui->actionExit->setText(tr("Exit"));

    ui->menuSettings->setTitle(tr("Setting"));
    ui->actionConfigration->setText(tr("Configration"));

    // 用户列表刷新
    connect(ui->actionRefresh, SIGNAL(triggered()),
            this, SLOT(userListRefreshTrigger()));

    // udp会话数据可读
    connect(&session, SIGNAL(ipMsgUdpSessionDataReady(QHostAddress, QByteArray)),
            this, SLOT(qIpMsgUdpSessionHandle(QHostAddress, QByteArray)));

    // 文件服务器数据可读
    connect(fileServer, SIGNAL(ipMsgFileServerDataReady(quint32, quint16, QByteArray)),
            this, SLOT(qIpMsgFileServerHandle(quint32, quint16, QByteArray)));

    // 用户列表更新
    connect(this, SIGNAL(userListUpdate()),
            this, SLOT(qIpMsgUserListUpdate()));

    // 用户列表被点击
    connect(ui->listWidgetUserList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
            this, SLOT(startChat(QListWidgetItem*)));

    // 设置动作触发信号槽
    connect(ui->actionConfigration, SIGNAL(triggered()),
            this, SLOT(qIpMsgConfigration()));

    // 英文动作触发信号槽
    connect(ui->actionEnglish, SIGNAL(triggered()),
            this, SLOT(qIpMsgLangtoEn()));

    // 中文动作触发信号槽
    connect(ui->actionChinese, SIGNAL(triggered()),
            this, SLOT(qIpMsgLangtoZh()));

    // 如果upd会话没有成功绑定,则弹框并退出程序
    if (session.mUdpBind != true) {
        QMessageBox::critical(this, tr("Error"), tr("Bind to udp port failed"), 1, 0, 0);
        qApp->closeAllWindows();
        exit(1);
    }

    // 如果文件服务器没有监听成功,则退出程序
    if (fileServer->mFileServerListen != true) {
        QMessageBox::critical(this, tr("Error"), tr("Listen to tcp port failed"), 1, 0, 0);
        qApp->closeAllWindows();
        exit(1);
    }

    // 如果udp会话有效,则使用udp会话进行用户刷新,否则关闭
    if (true == session.IpMsgUdpSessionValid()) {
        qout << session.IpMsgUdpSessionValid();
        // TODO : 自动刷新效果,注释后需要手动刷新
        //        session.ipMsgUserRefresh(&mSelf, mStartIp, mEndIp);
    } else {
        close(); // 然后进入 closeEvent 消息处理函数
    }
}

/**
 * @brief QIPMSG::~QIPMSG 析构函数
 */
QIPMSG::~QIPMSG()
{
    qout << "QIPMSG will close";
    delete ui;
}

/**
 * @brief slot 切换英文
 */
void QIPMSG::qIpMsgLangtoEn()
{
    if (qIpMsgLang != nullptr) {
        // Switch language to English.

        QApplication::instance()->removeTranslator(qIpMsgLang);
        ui->retranslateUi(this);
        // Notes: Please remember, do not delete qIpMsgLang every time.
        // delete(qIpMsgLang);
        // qIpMsgLang = nullptr;
        qIpMsgStatus(tr("Found") + " " + QString::number(mUsers.count(), 10) + " " + tr("users"));
    }
}

/**
 * @brief slot 切换英文
 */
void QIPMSG::qIpMsgLangtoZh()
{
    // Switch language to chinese.
    // Please remember, do not delete qIpMsgLang every time.
    if (qIpMsgLang == nullptr) {
        qIpMsgLang = new QTranslator();
    }
    qIpMsgLang->load(":/translations/translations_zh.qm");
    QApplication::instance()->installTranslator(qIpMsgLang);
    ui->retranslateUi(this);
    qIpMsgStatus(tr("Found") + " " + QString::number(mUsers.count(), 10) + " " + tr("users"));
}

/**
 * @brief 用指定的编码转到unicode编码
 * @param data
 * @return
 */
QString QIPMSG::toUnicode(QByteArray data)
{
    return QTextCodec::codecForName(mCodec.toStdString().c_str())->toUnicode(data);
}

/**
 * @brief 从unicode编码转到指定的编码
 * @param data
 * @return
 */
QByteArray QIPMSG::fromUnicode(QString data)
{
    return QTextCodec::codecForName(mCodec.toStdString().c_str())->fromUnicode(data);
}

/**
 * @brief 重写closeEvent处理函数,关闭前调用会话类的用户退出方法
 */
void QIPMSG::closeEvent(QCloseEvent* /*event*/)
{
    qout << "Close all chat windows";
    for (int i = 0; i < mUsers.count(); i++) {
        if (mUsers.at(i)->chatForm != nullptr) {
            mUsers.at(i)->chatForm->close();
            // delete(mUsers.at(i)->chatForm);
        }
    }
    if (true == session.IpMsgUdpSessionValid()) {
        session.ipMsgUserExit(&mSelf);
    }
}

/**
 * @brief slot 显示设置面板
 *
 */
void QIPMSG::qIpMsgConfigration()
{
    // 如果面板不存在,则构造一个面板
    if (mSetPanel == nullptr) {
        mSetPanel = new DialogSetting();
    }

    mSetPanel->setWindowTitle(tr("Configration"));
    mSetPanel->setUserName(toUnicode(mSelf.userId).toUtf8());
    mSetPanel->setUserNickName(toUnicode(mSelf.userNickName).toUtf8());
    mSetPanel->setGroupName(toUnicode(mSelf.userGroupName).toUtf8());
    mSetPanel->setStartIp(mStartIp);
    mSetPanel->setEndIp(mEndIp);

    // 面板构造出来后,关闭时会删除并赋值为nullptr,所以信号槽不会关联多次

    // 配置面板的关闭信号槽
    connect(mSetPanel, SIGNAL(setDialogClose()),
            this, SLOT(qIpMsgSettingsRejected()));

    // 配置面板的接受信号槽
    connect(mSetPanel, SIGNAL(setDialogAccepted()),
            this, SLOT(qIpMsgSettingsAccepted()));

    // 配置面板的拒绝信号槽
    connect(mSetPanel, SIGNAL(setDialogRejected()),
            this, SLOT(qIpMsgSettingsRejected()));

    // 面板显示
    mSetPanel->show();
}

/**
 * @brief slot 设置面板接收,然后删除并赋值为 nullptr
 */
void QIPMSG::qIpMsgSettingsAccepted()
{
    mSelf.userId        = fromUnicode(mSetPanel->getUserName());
    mSelf.userNickName  = fromUnicode(mSetPanel->getUserNickName());
    mSelf.userGroupName = fromUnicode(mSetPanel->getGroupName());

    mStartIp = QHostAddress(mSetPanel->getStartIp()).toIPv4Address();
    mEndIp   = QHostAddress(mSetPanel->getEndIp()).toIPv4Address();
    qout << "New configratuion:";
    qout << "Username:" << mSelf.userId
         << "NickName:" << mSelf.userNickName
         << "GroupName:" << mSelf.userGroupName;

    qout << "Username:" << QString(mSelf.userId)
         << "NickName:" << QString(mSelf.userNickName)
         << "GroupName:" << QString(mSelf.userGroupName);

    qout << "StartIP:" << QHostAddress(mStartIp).toString()
         << "EndIP:" << QHostAddress(mEndIp).toString();

    session.ipMsgUserRefresh(&mSelf, mStartIp, mEndIp);
    mSetPanel->close();
    delete mSetPanel;
    mSetPanel = nullptr;
}

/**
 * @brief 设置面板的拒接槽函数,删除设置面板,置 nullptr
 */
void QIPMSG::qIpMsgSettingsRejected()
{
    if (nullptr != mSetPanel) {
        delete mSetPanel;
        mSetPanel = nullptr;
    }
}

/**
 * @brief slot 用户列表刷新触发器
 */
void QIPMSG::userListRefreshTrigger()
{
    // Udp session is valid
    if (true == session.IpMsgUdpSessionValid()) {
        for (int i = 0; i < mUsers.count(); i++) {
            // Chat form is null or hidden.
            // -- 聊天表单为空或隐藏。
            // Need delete the chat form and delete user if no message unread.
            // -- 如果没有未读消息，需要删除聊天表单和删除用户。
            if ((mUsers.at(i)->chatForm == nullptr
                    || mUsers.at(i)->chatForm->isHidden())) {
                if (mUsers.at(i)->chatForm != nullptr) {
                    // Close the chat form window
                    mUsers.at(i)->chatForm->close();
                    // Delete the window
                    delete (mUsers.at(i)->chatForm);
                    qout << __FUNCTION__ << __LINE__;
                    mUsers.at(i)->chatForm = nullptr;
                }
                // No unread message for this user, delete user
                // -- 此用户无未读消息，删除用户
                if (mUsers.at(i)->blinkTimer == 0) {
                    delete (ui->listWidgetUserList->takeItem(i));
                    qout << __FUNCTION__ << __LINE__;
                    delete (mUsers.takeAt(i));
                    qout << __FUNCTION__ << __LINE__;
                }
            } else {
                // No new message but chat form is actived, then just hidden user from list  but not delete it.
                // -- 没有新的消息，但聊天形式是活跃的，然后只是从列表隐藏用户，但不删除它。
                if (mUsers.at(i)->blinkTimer == 0) {
                    ui->listWidgetUserList->item(i)->setHidden(true);
                }
            }
        }
        session.ipMsgUserRefresh(&mSelf, mStartIp, mEndIp);
    }
}

/**
 * @brief slot 更新用户列表
 */
void QIPMSG::qIpMsgUserListUpdate()
{
    int count = 0;
    ui->listWidgetUserList->clear();

    // IpMsgUserSort(mUsers);
    count = mUsers.count();
    qIpMsgStatus(tr("Found") + " " + QString::number(mUsers.count(), 10) + " " + tr("users"));

    for (int i = 0; i < count; i++) {
        ui->listWidgetUserList->addItem(new QListWidgetItem(QIcon(":/userIcon/chat.png"), toUnicode(mUsers.at(i)->userNickName) + "(" + toUnicode(mUsers.at(i)->userHostName) + ")" + "\n" + mUsers.at(i)->userHostAddr.toString()));
    }
}

/**
 * @brief 状态栏设置字符串
 * @param data
 */
void QIPMSG::qIpMsgStatus(QString data)
{
    ui->labelStatus->setText(data);
}

void QIPMSG::startChat(QListWidgetItem* item)
{
    int currentRow = ui->listWidgetUserList->currentIndex().row();

    item->setSelected(false);

    // Stop new message blink first for this chat form.
    if (mUsers.at(currentRow)->blinkTimer != 0) {
        killTimer(mUsers.at(currentRow)->blinkTimer);
        mUsers.at(currentRow)->blinkTimer = 0;
        mUsers.at(currentRow)->blinkFlag = 0;
    }
    // Update widget information
    ui->listWidgetUserList->item(currentRow)->setIcon(QIcon(":/userIcon/chat.png"));
    ui->listWidgetUserList->item(currentRow)->setTextColor(QColor("black"));

    // Update chat form information
    mUsers.at(currentRow)->chatForm->setWindowTitle(toUnicode(mUsers.at(currentRow)->userNickName));
    mUsers.at(currentRow)->updateChatFormHistory();
    mUsers.at(currentRow)->chatForm->setClient(mUsers.at(currentRow)->userVer);
    mUsers.at(currentRow)->chatForm->setUserName(toUnicode(mUsers.at(currentRow)->userId));
    mUsers.at(currentRow)->chatForm->setHost(mUsers.at(currentRow)->userHostAddr.toString());
    mUsers.at(currentRow)->chatForm->setGroupName(toUnicode(mUsers.at(currentRow)->userGroupName));
    // Shwo chat form.
    mUsers.at(currentRow)->chatForm->show();
}

void QIPMSG::qIpMsgChatSent(QString data, QHostAddress dest)
{
    QList<fileEntryT*> files;
    for (int i = 0; i < mUsers.count(); i++) {
        if (dest == mUsers.at(i)->userHostAddr) {
            if (data.length() > 0) {
                mUsers.at(i)->userPktSeq = g_pkg_seq++;
                // mUsers.at(i)->userPktSeq =(uint32_t)(time(nullptr));
                // Send chat content out
                session.ipMsgSendData(&mSelf, dest, fromUnicode(data));
                // Update Chat history in Chat form.
                mUsers.at(i)->appendChatHistory(toUnicode(mSelf.userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                mUsers.at(i)->appendChatHistory(data);
                mUsers.at(i)->appendChatHistory("\n");
                mUsers.at(i)->updateChatFormHistory();
                mUsers.at(i)->chatForm->getChat()->clear();
                mUsers.at(i)->offlineTimer = startTimer(200);
            }

            if (mUsers.at(i)->chatForm->fileList.count() > 0) {
                for (int j = 0; j < mUsers.at(i)->chatForm->fileList.count(); j++) {
                    if (mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus == FILE_TRANS_STATUS_IDLE
                        && mUsers.at(i)->chatForm->fileList.at(j)->fileOut == true) {
                        files.append(mUsers.at(i)->chatForm->fileList.at(j));
                        mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus = FILE_TRANS_STATUS_QUEUE;
                        mSelf.fileQueue.append(mUsers.at(i)->chatForm->fileList.at(j));
                        qout << "add new file to queue:" << mUsers.at(i)->chatForm->fileList.at(j)->info.fileName;
                    }
                }
                if (files.count() > 0)
                    session.ipMsgSendFiles(&mSelf, mUsers.at(i)->userHostAddr, files);
            }
            break;
        }
    }
}

void QIPMSG::timerEvent(QTimerEvent* event)
{
    int current_timer = event->timerId();
    for (int i = 0; i < mUsers.count(); i++) {
        // No data response, indicate user offline
        if (mUsers.at(i)->offlineTimer != 0
            && mUsers.at(i)->offlineTimer == current_timer) {
            killTimer(mUsers.at(i)->offlineTimer);
            mUsers.at(i)->offlineTimer = 0;
            if (mUsers.at(i)->userCfmSeq != mUsers.at(i)->userPktSeq) {
                mUsers.at(i)->appendChatHistory(toUnicode(mUsers.at(i)->userNickName + tr(" May be offline").toUtf8() + "\n"));
                mUsers.at(i)->updateChatFormHistory();
            }
            break;
        }
        // New message arrived, blink user icon
        else if (mUsers.at(i)->blinkTimer != 0
            && mUsers.at(i)->blinkTimer == current_timer) {
            if (mUsers.at(i)->blinkFlag % 2) {
                ui->listWidgetUserList->item(i)->setIcon(QIcon(":/userIcon/ipmsg.png"));
                ui->listWidgetUserList->item(i)->setTextColor(QColor("red"));
            } else {
                ui->listWidgetUserList->item(i)->setIcon(QIcon(":/userIcon/chat.png"));
                ui->listWidgetUserList->item(i)->setTextColor(QColor("black"));
            }
            mUsers.at(i)->blinkFlag++;
            break;
        }
    }
}

/**
 * @brief slot upd会话处理
 * @param src
 * @param data
 */
void QIPMSG::qIpMsgUdpSessionHandle(QHostAddress src, QByteArray data)
{
    IpMsgUser* user = nullptr;
    uint32_t pktCommand;
    uint8_t command;
    uint32_t commandOpt;
    QList<QByteArray> values;
    QList<QByteArray> others;
    QByteArray chatData;
    QList<QByteArray> files;

    int i = 0;
    qout << toUnicode (data);
    values = data.split(':');

    if (values.count() < 5) {
        qout << "Invalid pkt, ignore it";
        return;
    }

    for (i = 5; i < values.count(); i++) {
        chatData.append(values[i]);
        chatData.append(':');
    }

    pktCommand = values.at(4).toUInt();

    if (QString::number(pktCommand, 10) != values.at(4)) {
        qout << "Invalid command, ignore it";
        return;
    }

    command = pktCommand & 0x000000FF;
    commandOpt = pktCommand & 0xffffff00;
    // qout<<"Command:"<<"0x"+QString::number(command,16)<<"Opt:"<<"0x"+QString::number(commandOpt,16);

    if (IPMSG_BR_ENTRY == command
        || IPMSG_ANSENTRY == command) {
        for (i = 0; i < mUsers.count(); i++) {
            if (mUsers.at(i)->userHostAddr == src) {
                break;
            }
        }

        if (i != mUsers.count()) {
            user = mUsers.at(i);
        } else {
            user = new IpMsgUser();
            user->chatForm->main = this;
            connect(user->chatForm, SIGNAL(sent(QString, QHostAddress)), this, SLOT(qIpMsgChatSent(QString, QHostAddress)));
            connect(user->chatForm, SIGNAL(acceptFile(fileEntryT*)), this, SLOT(qIpMsgAcceptFile(fileEntryT*)));
            connect(user->chatForm, SIGNAL(rejectFile(fileEntryT*)), this, SLOT(qIpMsgRejectFile(fileEntryT*)));
            connect(user->chatForm, SIGNAL(recvfinish(quint32)), this, SLOT(qIpMsgRecvFileFinish(quint32)));
            connect(user->chatForm, SIGNAL(recverror(quint32)), this, SLOT(qIpMsgRecvFileError(quint32)));

        } // User information update

        user->userVer = values.at(0);
        mSelf.userPktSeq = values.at(1).toUInt();

        user->userId = values.at(2);

        user->userHostName = values.at(3);

        user->userHostAddr = src;

        if (chatData.length() > 0) {
            others = chatData.split(0);
            if (others.count() >= 1) {
                for (int i = 0; i < others.count(); i++) {
                    if (i == 0) {
                        user->userNickName = others.at(0);
                    } else if (i == 1) {
                        user->userGroupName = others.at(1);
                    }
                }
            }
        }
        if (i == mUsers.count()) {
            mUsers.append(user);
            ui->listWidgetUserList->addItem(new QListWidgetItem(QIcon(":/userIcon/chat.png"), toUnicode(mUsers.at(i)->userNickName) + "(" + toUnicode(mUsers.at(i)->userHostName) + ")" + "\n" + mUsers.at(i)->userHostAddr.toString()));
            qIpMsgStatus(tr("Found") + " " + QString::number(mUsers.count(), 10) + " " + tr("users"));
            // mUsers.at(i)->dumpUserInfo();
            // qout<<"Pkt Seq:"<<mSelf.userPktSeq;
        } else {
            ui->listWidgetUserList->item(i)->setText(toUnicode(mUsers.at(i)->userNickName) + "(" + toUnicode(mUsers.at(i)->userHostName) + ")" + "\n" + mUsers.at(i)->userHostAddr.toString());
        }
        ui->listWidgetUserList->item(i)->setTextColor(QColor("black"));
        ui->listWidgetUserList->item(i)->setHidden(false);

        if (IPMSG_BR_ENTRY == command) {
            session.ipMsgRespBr(&mSelf, mUsers.at(i));
        }
    } else if (IPMSG_SENDMSG == command) {
        for (i = 0; i < mUsers.count(); i++) {
            if (mUsers.at(i)->userHostAddr == src) {
                qout << "Found" << mUsers.at(i)->userHostAddr.toString();
                mSelf.userPktSeq = values.at(1).toUInt();
                if (mUsers.at(i)->chatForm == nullptr
                    || mUsers.at(i)->chatForm->isHidden()) {
                    mUsers.at(i)->blinkTimer = startTimer(500);
                    QApplication::alert(this);
                }
                break;
            }
        }

        if (IPMSG_FILEATTACHOPT & commandOpt) {
            files = chatData.split(0);
            qout << "File Msg from"
                 << "User:" << QString::number(i, 10) << values.at(3) << files;
            // Handle File attched requirment.
            if (i != mUsers.count()) {
                for (int k = 0; k < files.count(); k++) {
                    QList<QByteArray> fileList = files.at(k).split('\a');
                    for (int b = 0; b < fileList.count(); b++) {
                        QList<QByteArray> tmp = fileList.at(b).split(':');
                        if (tmp.count() > 5) {
                            fileEntryT* newFile = new fileEntryT();
                            newFile->fileOut = false;
                            newFile->fileId = tmp.at(0).toUInt();
                            newFile->info.fileName = tmp.at(1);
                            newFile->info.size = tmp.at(2).toUInt(nullptr, 16);
                            newFile->info.metadataChangeTime = tmp.at(3).toUInt(nullptr, 16);
                            newFile->info.permission = tmp.at(4).toUInt(nullptr, 16);
                            newFile->fileHost = mUsers.at(i)->userHostAddr.toIPv4Address();
                            newFile->fileTranStatus = FILE_TRANS_STATUS_IDLE;
                            if (newFile->info.permission != IPMSG_FILE_REGULAR) {

                                qout << "Not support file type" << newFile->info.permission;
                                mUsers.at(i)->appendChatHistory(toUnicode(mUsers.at(i)->userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                                mUsers.at(i)->appendChatHistory(tr("Do not support directory") + "\"" + toUnicode(tmp.at(1)) + "\"" + "\n");
                                mUsers.at(i)->updateChatFormHistory();
                                delete newFile;
                                continue;
                            }
                            mUsers.at(i)->chatForm->addRemoteShareFile(newFile);
                            qout << "Add" << tmp.at(1);
                        }
                    }
                }
            }
        } else {
            qout << "Receive Msg from"
                 << "User:" << QString::number(i, 10) << values.at(3) << ":" + chatData.split(0).at(0);
        }

        if (commandOpt & IPMSG_SENDCHECKOPT) {
            if (i != mUsers.count()) {
                // qDebug("Need resp");
                session.ipMsgRespOK(&mSelf, mUsers.at(i));
                mUsers.at(i)->chatForm->setWindowTitle(toUnicode(mUsers.at(i)->userNickName));
                if (!(IPMSG_FILEATTACHOPT & commandOpt)) {
                    mUsers.at(i)->appendChatHistory(toUnicode(mUsers.at(i)->userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                    mUsers.at(i)->appendChatHistory(toUnicode(chatData.split(0).at(0) + "\n"));
                    mUsers.at(i)->updateChatFormHistory();
                }
                mUsers.at(i)->chatForm->setClient(mUsers.at(i)->userVer);
                mUsers.at(i)->chatForm->setUserName(toUnicode(mUsers.at(i)->userId));
                mUsers.at(i)->chatForm->setHost(mUsers.at(i)->userHostAddr.toString());
                mUsers.at(i)->chatForm->setGroupName(toUnicode(mUsers.at(i)->userGroupName));
            }
        }
    } else if (IPMSG_RECVMSG == command) {
        mSelf.userPktSeq = values.at(1).toUInt();
        for (i = 0; i < mUsers.count(); i++) {
            if (mUsers.at(i)->userHostAddr == src) {
                if (mUsers.at(i)->offlineTimer != 0) {
                    killTimer(mUsers.at(i)->offlineTimer);
                    mUsers.at(i)->offlineTimer = 0;
                }
                mUsers.at(i)->userCfmSeq = chatData.split(0).at(0).toUInt();
                // qout<<"Got cfm "<<mUsers.at(i)->userCfmSeq<<"from"<<src.toString();
                break;
            }
        }
    } else if (IPMSG_BR_EXIT == command) {
        mSelf.userPktSeq = values.at(1).toUInt();
        for (i = 0; i < mUsers.count(); i++) {
            if (mUsers.at(i)->userHostAddr == src) {
                if (mUsers.at(i)->blinkTimer == 0) {
                    qout << "will hidden" << src.toString();
                    ui->listWidgetUserList->item(i)->setHidden(true);
                } else {
                    qout << "Now message did not display, can not hidden it";
                }
                break;
            }
        }
        qIpMsgStatus(tr("Found") + " " + QString::number(mUsers.count(), 10) + " " + tr("users"));
    }
}

/**
 * @brief slot 文件服务器处理
 * @param ip
 * @param port
 * @param data
 */
void QIPMSG::qIpMsgFileServerHandle(quint32 ip, quint16 port, QByteArray data)
{
    uint32_t reqFileId = 0;
    uint32_t command;

    QHostAddress addr;

    QByteArray dataSample = "1_lbt80_0#160#FC4DD4D98024#0#0#0#4000#9:1546091332:caoweigang:CAOWEIGANG:96:5:2710:0:";
    QList<QByteArray> value = data.split(':');

    addr.setAddress(ip);
    qout << "Handle data" << data << "From" << addr.toString() << "Port:" << port;
    if (value.count() > 8) {
        command = value.at(4).toUInt(nullptr, 10) & 0xff;
        reqFileId = value.at(6).toUInt(nullptr, 16);

        qout << "TCP Command:" << command << "File Id:" << reqFileId;

        if (command != IPMSG_GETFILEDATA) {
            return;
        }
    } else {
        qout << "Error" << __FUNCTION__ << __LINE__;
        return;
    }

    for (int i = 0; i < mSelf.fileQueue.size(); i++) {
        if (reqFileId == mSelf.fileQueue.at(i)->fileId
            && ip == mSelf.fileQueue.at(i)->fileHost
            && mSelf.fileQueue.at(i)->fileTranStatus == FILE_TRANS_STATUS_QUEUE
            && mSelf.fileQueue.at(i)->fileOut == true) {
            mSelf.fileQueue.at(i)->filePort = port;
            mSelf.fileQueue.at(i)->fileTranStatus = FILE_TRANS_STATUS_RUN;
            {
                FileTransWorker* trans = new FileTransWorker();
                trans->mFilename = mSelf.fileQueue.at(i)->info.absoluteFilePath;
                trans->mFileId = mSelf.fileQueue.at(i)->fileId;
                trans->mHandle = (fileServer->fileServerSockMatch(mSelf.fileQueue.at(i)->fileHost, mSelf.fileQueue.at(i)->filePort))->socketDescriptor();

                // qout<<"Got File"<<trans->mFilename<<"Sock"<<trans->mSock->peerAddress().toString()<<trans->mSock->peerPort();

                connect(trans, SIGNAL(fileTransProgress(quint32, int)), this, SLOT(qIpMsgFileTransProgress(quint32, int)));
                connect(trans, SIGNAL(fileTransFinished(quint32)), this, SLOT(qIpMsgFileTransFinished(quint32)));
                connect(trans, SIGNAL(fileTransError(quint32, int)), this, SLOT(qIpMsgFileTransError(quint32, int)));
                QThread* thread = new QThread();
                trans->moveToThread(thread);
                connect(thread, SIGNAL(started()), trans, SLOT(fileTransStart()));
                // connect(trans, SIGNAL(fileTransFinished()), thread, SLOT(quit()));
                connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
                connect(thread, SIGNAL(finished()), trans, SLOT(deleteLater()));
                thread->start();
            }
            mSelf.fileQueue.removeAt(i);
            break;
        }
    }
}

/**
 * @brief slot 文件传输进度
 * @param fileId
 * @param progress
 */
void QIPMSG::qIpMsgFileTransProgress(quint32 fileId, int progress)
{
    // qout<<"File ID"<<fileId<<"Progress"<<progress;
    // qout<<"SendFile SLOT:"<<QThread::currentThreadId();
    for (int i = 0; i < mUsers.count(); i++) {
        if (mUsers.at(i)->chatForm != nullptr) {
            for (int j = 0; j < mUsers.at(i)->chatForm->fileList.count(); j++) {
                if (mUsers.at(i)->chatForm->fileList.at(j)->fileId == fileId
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileOut == true) {
                    mUsers.at(i)->chatForm->updateFileProgress(j, progress);
                    return;
                }
            }
        }
    }
}

/**
 * @brief slot 文件传输错误
 * @param fileId
 * @param progress
 */
void QIPMSG::qIpMsgFileTransError(quint32 fileId, int progress)
{
    // qout<<"File ID"<<fileId<<"Progress"<<progress;
    for (int i = 0; i < mUsers.count(); i++) {
        if (mUsers.at(i)->chatForm != nullptr) {
            for (int j = 0; j < mUsers.at(i)->chatForm->fileList.count(); j++) {
                if (mUsers.at(i)->chatForm->fileList.at(j)->fileId == fileId
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileOut == true) {
                    mUsers.at(i)->appendChatHistory(toUnicode(mSelf.userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                    mUsers.at(i)->appendChatHistory(tr("Send") + " \"" + mUsers.at(i)->chatForm->fileList.at(j)->info.absoluteFilePath + "\" " + tr("error"));
                    mUsers.at(i)->appendChatHistory("\n");
                    mUsers.at(i)->updateChatFormHistory();
                    mUsers.at(i)->chatForm->updateFileError(j, progress);
                    mUsers.at(i)->chatForm->delFixedShareFile(j);
                    return;
                }
            }
        }
    }
}

/**
 * @brief slot 文件传输结束
 * @param fileId
 */
void QIPMSG::qIpMsgFileTransFinished(quint32 fileId)
{
    int i = 0;
    qout << "File ID" << fileId << "trans finished";
    for (i = 0; i < mUsers.count(); i++) {
        if (mUsers.at(i)->chatForm != nullptr) {
            for (int j = 0; j < mUsers.at(i)->chatForm->fileList.count(); j++) {
                if (mUsers.at(i)->chatForm->fileList.at(j)->fileId == fileId
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileOut == true) {
                    mUsers.at(i)->appendChatHistory(toUnicode(mSelf.userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                    mUsers.at(i)->appendChatHistory(tr("Send") + " \"" + mUsers.at(i)->chatForm->fileList.at(j)->info.absoluteFilePath + "\" " + tr("finished"));
                    mUsers.at(i)->appendChatHistory("\n");
                    mUsers.at(i)->updateChatFormHistory();
                    mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus = FILE_TRANS_STATUS_FINISHED;
                    mUsers.at(i)->chatForm->delFixedShareFile(j);
                    return;
                }
            }
        }
    }
}

/**
 * @brief slot 接受文件结束
 * @param fileId
 */
void QIPMSG::qIpMsgRecvFileFinish(quint32 fileId)
{
    FormChat* form = qobject_cast<FormChat*>(sender());
    IpMsgUser* user = nullptr;
    int j = 0;
    int i = 0;
    if (form != nullptr) {

        for (j = 0; j < mUsers.count(); j++) {
            if (form == mUsers.at(j)->chatForm) {
                user = mUsers.at(j);
                break;
            }
        }
        if (j == mUsers.count())
            return;

        for (i = 0; i < form->fileList.count(); i++) {
            if (form->fileList.at(i)->fileId == fileId
                && form->fileList.at(i)->fileOut == false
                && form->fileList.at(i)->fileTranStatus == FILE_TRANS_STATUS_FINISHED) {
                user->appendChatHistory(toUnicode(user->userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                user->appendChatHistory(tr("Receive") + " \"" + form->fileList.at(i)->info.absoluteFilePath + "\" " + tr("finished"));
                user->appendChatHistory("\n");
                user->updateChatFormHistory();
                form->fileList.removeAt(i);
                break;
            }
        }
    }
}

/**
 * @brief slot 接收文件错误
 * @param fileId
 */
void QIPMSG::qIpMsgRecvFileError(quint32 fileId)
{
    FormChat* form = qobject_cast<FormChat*>(sender());
    IpMsgUser* user = nullptr;
    int j = 0;
    int i = 0;
    if (form != nullptr) {
        for (j = 0; j < mUsers.count(); j++) {
            if (form == mUsers.at(j)->chatForm) {
                user = mUsers.at(j);
                break;
            }
        }
        if (j == mUsers.count())
            return;

        for (i = 0; i < form->fileList.count(); i++) {
            if (form->fileList.at(i)->fileId == fileId
                && form->fileList.at(i)->fileOut == false
                && form->fileList.at(i)->fileTranStatus == FILE_TRANS_STATUS_FINISHED) {
                user->appendChatHistory(toUnicode(user->userNickName + " " + QDateTime::currentDateTime().toString("hh:mm:ss").toUtf8() + "\n"));
                user->appendChatHistory(tr("Receive") + " \"" + form->fileList.at(i)->info.absoluteFilePath + "\" " + tr("error"));
                user->appendChatHistory("\n");
                user->updateChatFormHistory();
                form->fileList.removeAt(i);
                break;
            }
        }
    }
}

/**
 * @brief slot 接受文件
 * @param file
 */
void QIPMSG::qIpMsgAcceptFile(fileEntryT* file)
{
    qout << "Accept file" << file->info.fileName;
    for (int i = 0; i < mUsers.count(); i++) {
        if (mUsers.at(i)->userHostAddr.toIPv4Address() == file->fileHost) {
            for (int j = 0; j < mUsers.at(i)->chatForm->fileList.count(); j++) {
                if (mUsers.at(i)->chatForm->fileList.at(j)->fileId == file->fileId
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileOut == false
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus == FILE_TRANS_STATUS_IDLE) {
                    mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus = FILE_TRANS_STATUS_QUEUE;
                    mUsers.at(i)->fileQueue.append(mUsers.at(i)->chatForm->fileList.at(j));
#if 1
                    mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus = FILE_TRANS_STATUS_RUN;
                    IpMsgFileRecv* recv = new IpMsgFileRecv(&mSelf, file);
                    connect(recv->client, SIGNAL(ipMsgFileClientErrorSig(quint32, int)), mUsers.at(i)->chatForm, SLOT(fileRecvError(quint32, int)));
                    connect(recv->client, SIGNAL(ipMsgFileClientProgressSig(quint32, int)), mUsers.at(i)->chatForm, SLOT(fileRecvProgress(quint32, int)));
                    connect(recv->client, SIGNAL(ipMsgFileClientFinishSig(quint32)), mUsers.at(i)->chatForm, SLOT(fileRecvFinished(quint32)));
                    connect(mUsers.at(i)->chatForm, SIGNAL(cancelFile(fileEntryT*)), recv, SLOT(ipMsgFileClientCancel(fileEntryT*)));
#endif
                    break;
                }
            }
            break;
        }
    }
}

/**
 * @brief slot 拒收文件
 * @param file
 */
void QIPMSG::qIpMsgRejectFile(fileEntryT* file)
{
    qout << "Reject file" << file->info.fileName;

    for (int i = 0; i < mUsers.count(); i++) {
        if (mUsers.at(i)->userHostAddr.toIPv4Address() == file->fileHost) {
            for (int j = 0; j < mUsers.at(i)->chatForm->fileList.count(); j++) {
                if (mUsers.at(i)->chatForm->fileList.at(j)->fileId == file->fileId
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileOut == false
                    && mUsers.at(i)->chatForm->fileList.at(j)->fileTranStatus == FILE_TRANS_STATUS_IDLE) {
                    mUsers.at(i)->chatForm->delFixedRemoteShareFile(j);
                    break;
                }
            }
        }
    }
}
